/*=============================================================================
PostProcessFilters : image filters post processing
Copyright (c) 2001 Crytek Studios. All Rights Reserved.

Revision history:
* 23/02/2005: Re-factored/Converted to CryEngine 2.0 by Tiago Sousa
* Created by Tiago Sousa

=============================================================================*/

#include "StdAfx.h"
#include "DriverD3D.h"
#include "I3DEngine.h"
#include "D3DPostProcess.h"
#include "D3DStereo.h"

#pragma warning(disable: 4244)

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// todo: handle diferent sharpening filters

void CFilterSharpening::Render()
{ 
  PROFILE_LABEL_PUSH( "SHARPENING" );

  GetUtils().StretchRect(CTexture::s_ptexBackBuffer, CTexture::s_ptexBackBufferScaled[0]);    

  static CCryNameTSCRC pTechName("BlurInterpolation");
  GetUtils().ShBeginPass(CShaderMan::m_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);   

  gcpRendD3D->FX_SetState(GS_NODEPTHTEST);     
  float fType = m_pType->GetParam();
  float fAmount = m_pAmount->GetParam();

  // Set PS default params
  Vec4 pParams= Vec4(0, 0, 0, fAmount);
  static CCryNameR pParamName("psParams");
  CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName, &pParams, 1);

  GetUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_POINT);   
  GetUtils().SetTexture(CTexture::s_ptexBackBufferScaled[0], 1);    
  GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight()); 

  GetUtils().ShEndPass();   

  PROFILE_LABEL_POP( "SHARPENING" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// todo: handle diferent blurring filters, add wavelength based blur

void CFilterBlurring::Render()
{  
  PROFILE_LABEL_PUSH( "BLURRING" );

  float fType = m_pType->GetParam();
  float fAmount = m_pAmount->GetParam();
  fAmount = clamp_tpl<float>(fAmount, 0.0f, 1.0f);

  // maximum blur amount to have nice results
  const float fMaxBlurAmount = 5.0f;

  // this is uber expensive - and barely no need for this - adjusting gaussian distribution already looks quite good
  //GetUtils().TexBlurGaussian(CTexture::s_ptexBackBuffer, 1, 1.0f, LERP(0.0f, fMaxBlurAmount, sqrtf(fAmount) ), false);             

  GetUtils().StretchRect(CTexture::s_ptexBackBuffer, CTexture::s_ptexBackBufferScaled[0]);    
  GetUtils().TexBlurGaussian(CTexture::s_ptexBackBufferScaled[0], 1, 1.0f, LERP(0.0f, fMaxBlurAmount, fAmount), false, 0, false, CTexture::s_ptexBackBufferScaledTemp[0]);             

  static CCryNameTSCRC pTechName("BlurInterpolation");
  GetUtils().ShBeginPass(CShaderMan::m_shPostEffects, pTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);   

  gcpRendD3D->FX_SetState(GS_NODEPTHTEST);     

  // Set PS default params  
  Vec4 pParams= Vec4(0, 0, 0, fAmount * fAmount);
  static CCryNameR pParamName("psParams");
  CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName, &pParams, 1);

  GetUtils().SetTexture(CTexture::s_ptexBackBufferScaled[0], 0);    
  GetUtils().SetTexture(CTexture::s_ptexBackBuffer, 1, FILTER_POINT);     
  GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight()); 

  GetUtils().ShEndPass();   

  PROFILE_LABEL_POP( "BLURRING" );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

bool CColorGrading::UpdateParams( SColorGradingMergeParams &pMergeParams )
{
	float fSharpenAmount = max(m_pSharpenAmount->GetParam(), 0.0f);

	// add cvar color_grading/color_grading_levels/color_grading_selectivecolor/color_grading_filters

	// Clamp to same Photoshop min/max values
	float fMinInput = clamp_tpl<float>(m_pMinInput->GetParam(), 0.0f, 255.0f);
	float fGammaInput = clamp_tpl<float>(m_pGammaInput->GetParam(), 0.0f, 10.0f);;
	float fMaxInput = clamp_tpl<float>(m_pMaxInput->GetParam(), 0.0f, 255.0f);
	float fMinOutput = clamp_tpl<float>(m_pMinOutput->GetParam(), 0.0f, 255.0f);

	float fMaxOutput = clamp_tpl<float>(m_pMaxOutput->GetParam(), 0.0f, 255.0f);

	float fBrightness = m_pBrightness->GetParam();
	float fContrast = m_pContrast->GetParam();
	float fSaturation = m_pSaturation->GetParam() + m_pSaturationOffset->GetParam();
	Vec4  pFilterColor = m_pPhotoFilterColor->GetParamVec4() + m_pPhotoFilterColorOffset->GetParamVec4();
	float fFilterColorDensity = clamp_tpl<float>(m_pPhotoFilterColorDensity->GetParam() + m_pPhotoFilterColorDensityOffset->GetParam(), 0.0f, 1.0f);
	float fGrain = min(m_pGrainAmount->GetParam()+m_pGrainAmountOffset->GetParam(), 1.0f);

	Vec4 pSelectiveColor = m_pSelectiveColor->GetParamVec4();
	float fSelectiveColorCyans = clamp_tpl<float>(m_pSelectiveColorCyans->GetParam()*0.01f, -1.0f, 1.0f);
	float fSelectiveColorMagentas = clamp_tpl<float>(m_pSelectiveColorMagentas->GetParam()*0.01f, -1.0f, 1.0f);
	float fSelectiveColorYellows = clamp_tpl<float>(m_pSelectiveColorYellows->GetParam()*0.01f, -1.0f, 1.0f);
	float fSelectiveColorBlacks = clamp_tpl<float>(m_pSelectiveColorBlacks->GetParam()*0.01f, -1.0f, 1.0f);

	// Saturation matrix
	Matrix44 pSaturationMat;      
	{
		float y=0.3086f, u=0.6094f, v=0.0820f, s=clamp_tpl<float>(fSaturation, -1.0f, 100.0f);  

		float a = (1.0f-s)*y + s;
		float b = (1.0f-s)*y;
		float c = (1.0f-s)*y;
		float d = (1.0f-s)*u;
		float e = (1.0f-s)*u + s;
		float f = (1.0f-s)*u;
		float g = (1.0f-s)*v;
		float h = (1.0f-s)*v;
		float i = (1.0f-s)*v + s;

		pSaturationMat.SetIdentity();
		pSaturationMat.SetRow(0, Vec3(a, d, g));  
		pSaturationMat.SetRow(1, Vec3(b, e, h));
		pSaturationMat.SetRow(2, Vec3(c, f, i));                                     
	}

	//  Brightness matrix
	Matrix44 pBrightMat;
	fBrightness=clamp_tpl<float>(fBrightness, 0.0f, 100.0f);    
	pBrightMat.SetIdentity();
	pBrightMat.SetRow(0, Vec3(fBrightness, 0, 0)); 
	pBrightMat.SetRow(1, Vec3(0, fBrightness, 0));
	pBrightMat.SetRow(2, Vec3(0, 0, fBrightness));            

	// Create Contrast matrix
	Matrix44 pContrastMat;
	{
		float c=clamp_tpl<float>(fContrast, -1.0f, 100.0f);  
		pContrastMat.SetIdentity();
		pContrastMat.SetRow(0, Vec3(c, 0, 0));  
		pContrastMat.SetRow(1, Vec3(0, c, 0));
		pContrastMat.SetRow(2, Vec3(0, 0, c));              
		pContrastMat.SetColumn(3, 0.5f*Vec3(1.0f-c, 1.0f-c, 1.0f-c));  
	}

	// Compose final color matrix and set fragment program constants
	Matrix44 pColorMat = pSaturationMat * (pBrightMat * pContrastMat);      

	Vec4 pParams0 = Vec4(fMinInput, fGammaInput, fMaxInput, fMinOutput);
	Vec4 pParams1 = Vec4(fMaxOutput, fGrain, cry_rand()%1024, cry_rand()%1024);
	Vec4 pParams2 = Vec4(pFilterColor.x, pFilterColor.y, pFilterColor.z, fFilterColorDensity);
	Vec4 pParams3 = Vec4(pSelectiveColor.x, pSelectiveColor.y, pSelectiveColor.z, fSharpenAmount + 1.0f);
	Vec4 pParams4 = Vec4(fSelectiveColorCyans, fSelectiveColorMagentas, fSelectiveColorYellows, fSelectiveColorBlacks);    

	// Enable corresponding shader variation
	pMergeParams.nFlagsShaderRT = gRenDev->m_RP.m_FlagsShader_RT;
	pMergeParams.nFlagsShaderRT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1]|g_HWSR_MaskBit[HWSR_SAMPLE2]|g_HWSR_MaskBit[HWSR_SAMPLE3]|g_HWSR_MaskBit[HWSR_SAMPLE4]|g_HWSR_MaskBit[HWSR_SAMPLE5]);

	if( CRenderer::CV_r_colorgrading_levels && (fMinInput || fGammaInput || fMaxInput || fMinOutput ||fMaxOutput) )
		pMergeParams.nFlagsShaderRT |= g_HWSR_MaskBit[HWSR_SAMPLE0];

	if( CRenderer::CV_r_colorgrading_filters && (fFilterColorDensity || fGrain || fSharpenAmount))
	{
		if( fFilterColorDensity )
			pMergeParams.nFlagsShaderRT |= g_HWSR_MaskBit[HWSR_SAMPLE4];
		if( fGrain || fSharpenAmount )
			pMergeParams.nFlagsShaderRT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
	}

	if( CRenderer::CV_r_colorgrading_selectivecolor && (fSelectiveColorCyans || fSelectiveColorMagentas || fSelectiveColorYellows || fSelectiveColorBlacks))
		pMergeParams.nFlagsShaderRT |= g_HWSR_MaskBit[HWSR_SAMPLE2];

	Matrix44 pColorMatFromUserAndTOD = GetUtils().GetColorMatrix();
	pColorMat = pColorMat  * pColorMatFromUserAndTOD;
	
	Vec4 pColorMatrix[3]=
	{
		Vec4(pColorMat.m00, pColorMat.m01, pColorMat.m02, pColorMat.m03),
		Vec4(pColorMat.m10, pColorMat.m11, pColorMat.m12, pColorMat.m13), 
		Vec4(pColorMat.m20, pColorMat.m21, pColorMat.m22, pColorMat.m23),
	};

	pMergeParams.pColorMatrix[0] = pColorMatrix[0];
	pMergeParams.pColorMatrix[1] = pColorMatrix[1];
	pMergeParams.pColorMatrix[2] = pColorMatrix[2];
	pMergeParams.pLevels[0] = pParams0;
	pMergeParams.pLevels[1] = pParams1;
	pMergeParams.pFilterColor = pParams2;
	pMergeParams.pSelectiveColor[0] = pParams3;
	pMergeParams.pSelectiveColor[1] = pParams4;

	// Always using color charts

	if (gcpRendD3D->m_pColorGradingControllerD3D && (gRenDev->GetFrameID(false) % max(1, CRenderer::CV_r_ColorgradingChartsCache)) == 0)
	{    
		if(!gcpRendD3D->m_pColorGradingControllerD3D->Update(&pMergeParams))
			return false;
	}

	// If using merged color grading with color chart disable regular color transformations in display - only need to use color chart
	pMergeParams.nFlagsShaderRT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE2]|g_HWSR_MaskBit[HWSR_SAMPLE4]);
	
	//// Always using color charts - %SAMPLE5 for defining volume lookup 
	//if( gcpRendD3D->m_pColorGradingControllerD3D && gcpRendD3D->m_pColorGradingControllerD3D->GetColorChart() && gcpRendD3D->m_pColorGradingControllerD3D->GetColorChart()->GetTexType() == eTT_3D)
	//	pMergeParams.nFlagsShaderRT |= g_HWSR_MaskBit[HWSR_SAMPLE5];

	return true;
}

void CColorGrading::Render()
{
	// Depreceated: to be removed / replaced by UberPostProcess shader
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool CPostAA::Preprocess()
{
	CTexture *pCurrRT = PostProcessUtils().GetMsaaRT( true );
	CTexture *pPrevRT = PostProcessUtils().GetMsaaRT( false );
	if( !pCurrRT || !pPrevRT) 
	{
		m_bInit = true;
		return false;
	}

	if( CRenderer::CV_r_PostAAMode == 2 )
	{
		if (m_pScopeZoom->GetParam() > 0.5f)
			m_nScopeZoomTransition = 10;
		else if (m_nScopeZoomTransition)
			m_nScopeZoomTransition--;
	}

	return true;
}

void CPostAA::Render()
{	
	if(!gRenDev->IsHDRModeEnabled())
		return;

	GPU_TIMER_START("POST_AA");
	PROFILE_LABEL_PUSH( "POST_AA" );

	PROFILE_SHADER_START;

	static CCryNameTSCRC TechName("PostAA");
	CShader *pShader = CShaderMan::m_shPostAA;

#if !defined(XENON)
	if( gcpRendD3D->IsHDRModeEnabled() && CRenderer::CV_r_PostAA && !gRenDev->m_RP.m_MSAAData.Type) 
		gcpRendD3D->FX_PopRenderTarget(0);
#endif

	const CPostEffect * pSceneRain = PostEffectMgr()->GetEffect(ePFX_SceneRain);
	const N3DEngineCommon::SRainInfo & rainInfo = gcpRendD3D->m_p3DEngineCommon.m_RainInfo;
  const bool bApplyRain = pSceneRain && pSceneRain->IsActive()
    && CRenderer::CV_r_UseMergedPosts
    && CTexture::IsTextureExist(CTexture::s_ptexRainDrops)
    && rainInfo.m_bRainDrops;

	if( !CRenderer::CV_r_PostAA )
		m_bInit = true;

  // only needed when rain or screen scratches used and post msaa disabled
  if( !CRenderer::CV_r_PostAA && bApplyRain)
  {
    PostProcessUtils().CopyScreenToTexture(CTexture::s_ptexBackBuffer);
    CTexture::s_ptexBackBuffer->SetResolved(true);
  }

	// reset flags properly
	uint64 nSaveFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
	gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1]|g_HWSR_MaskBit[HWSR_SAMPLE2]|g_HWSR_MaskBit[HWSR_SAMPLE3]);

	if (bApplyRain)
		gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];

	if (gcpRendD3D->IsHDRModeEnabled() && (!CRenderer::CV_r_PostAA || gRenDev->m_RP.m_MSAAData.Type) )
	{
		// Separate pass for rain only (if no post AA is used or not already done in sunshafts pass)
		// TODO: ideally merge with some pass that is rendered in halfres
		if (bApplyRain)
		{
			GetUtils().ShBeginPass(CShaderMan::m_shPostEffects, TechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);                    
			gcpRendD3D->SetCullMode( R_CULL_NONE );
			gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
			const Vec4 vRainCol(rainInfo.m_vColor, 1.f);
			static CCryNameR pRainParam("vRainColor");
			pShader->FXSetPSFloat(pRainParam, &vRainCol, 1);
			GetUtils().SetTexture(CTexture::s_ptexRainDrops, 4, FILTER_LINEAR);
			GetUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_POINT);        
			SD3DPostEffectsUtils::DrawFullScreenQuadWPOS(CTexture::s_ptexBackBuffer->GetWidth(),CTexture::s_ptexBackBuffer->GetHeight());
			GetUtils().ShEndPass();                    			
		}
		
    gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;
		
    if( CRenderer::CV_r_PostAAEdgeFilter < 2 || gRenDev->m_RP.m_MSAAData.Type)
		{
			PROFILE_SHADER_END
			PROFILE_LABEL_POP( "POST_AA" );
			GPU_TIMER_STOP("POST_AA");
			return;
		}
	}

	CTexture *pCurrRT = PostProcessUtils().GetMsaaRT( true );
	CTexture *pPrevRT = PostProcessUtils().GetMsaaRT( false );







	gcpRendD3D->m_RP.m_PersFlags2 |= RBPF2_NOPOSTAA;

	// todo: consoles version
	CTexture *pEdgesTex = CTexture::s_ptexStereoL;
	CTexture *pBlendTex = CTexture::s_ptexStereoR;
	CTexture *pFinaltex = CTexture::s_ptexStereoL;

	// todo: disable temporarily for DX9 since not fully working, needs to be investigated
#if defined(DIRECT3D10) 

	if( CRenderer::CV_r_PostAAEdgeFilter && !gRenDev->m_RP.m_MSAAData.Type && pEdgesTex && pBlendTex)
	{
		////////////////////////////////////////////////////////////////////////////////////////////////
		// 1st pass: generate edges texture
		gcpRendD3D->FX_PushRenderTarget(0, pEdgesTex, &gcpRendD3D->m_DepthBufferOrig);

		ColorF clearColor(0, 0, 0, 0);
		gcpRendD3D->EF_ClearBuffers(FRT_CLEAR_COLOR|FRT_CLEAR_IMMEDIATE, &clearColor);

		static CCryNameTSCRC pszLumaEdgeDetectTechName("LumaEdgeDetectionSMAA");
		static const CCryNameR pPostAAParams("PostAAParams");

		const int iWidth = gcpRendD3D->GetWidth();
		const int iHeight = gcpRendD3D->GetHeight();
		gcpRendD3D->RT_SetViewport(0, 0, iWidth, iHeight);

		GetUtils().ShBeginPass(pShader, pszLumaEdgeDetectTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

		gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
		if( CRenderer::CV_r_PostAAStencilCulling )
			GetUtils().BeginStencilPrePass(false, false);
		
		Vec4 pParam(1.f/iWidth, 1.f/iHeight, 0.f, 0.f);
		pShader->FXSetVSFloat(pPostAAParams, &pParam, 1);

		GetUtils().SetTexture( pCurrRT, 0, FILTER_POINT);
		SD3DPostEffectsUtils::DrawFullScreenQuadWPOS(iWidth, iHeight);

		GetUtils().ShEndPass();

		GetUtils().EndStencilPrePass();
		
		gcpRendD3D->FX_PopRenderTarget(0);

		if( CRenderer::CV_r_PostAAStencilCulling )
		{



	//	gcpRendD3D->FX_StencilRefresh(STENC_FUNC(FSS_STENCFUNC_EQUAL), gcpRendD3D->m_nStencilMaskRef);

		}

		////////////////////////////////////////////////////////////////////////////////////////////////
		// 2nd pass: generate blend texture
		gcpRendD3D->FX_PushRenderTarget(0, pBlendTex, &gcpRendD3D->m_DepthBufferOrig);
		gcpRendD3D->EF_ClearBuffers(FRT_CLEAR_COLOR|FRT_CLEAR_IMMEDIATE, &clearColor);

		static CCryNameTSCRC pszBlendWeightTechName("BlendWeightSMAA");
		GetUtils().ShBeginPass(pShader, pszBlendWeightTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

		gcpRendD3D->FX_SetState(GS_NODEPTHTEST);

		if( CRenderer::CV_r_PostAAStencilCulling )
			gcpRendD3D->FX_StencilTestCurRef(true, false);
		
		pShader->FXSetVSFloat(pPostAAParams, &pParam, 1);

		GetUtils().SetTexture( pEdgesTex, 0, FILTER_LINEAR);
		GetUtils().SetTexture( m_pAreaSMAA, 1, FILTER_LINEAR);
		GetUtils().SetTexture( m_pSearchSMAA, 2, FILTER_POINT);

		SD3DPostEffectsUtils::DrawFullScreenQuadWPOS(iWidth, iHeight);

		GetUtils().ShEndPass();
		
		gcpRendD3D->FX_PopRenderTarget(0);

		if( CRenderer::CV_r_PostAAStencilCulling )
			gcpRendD3D->FX_StencilTestCurRef(false);

		////////////////////////////////////////////////////////////////////////////////////////////////
		//gcpRendD3D->FX_PushRenderTarget(0, pFinaltex, NULL);

		// final pass - blend neighborhood pixels
		static CCryNameTSCRC pszBlendNeighborhoodTechName("NeighborhoodBlendingSMAA");
		GetUtils().ShBeginPass(pShader, pszBlendNeighborhoodTechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

		gcpRendD3D->FX_SetState(GS_NODEPTHTEST);
		//gcpRendD3D->FX_StencilTestCurRef(true, false);
		
		pShader->FXSetVSFloat(pPostAAParams, &pParam, 1);

		GetUtils().SetTexture( pBlendTex, 0, FILTER_POINT);
		GetUtils().SetTexture(pCurrRT, 1, FILTER_LINEAR);
		GetUtils().SetTexture(pEdgesTex, 2, FILTER_POINT);
		
		SD3DPostEffectsUtils::DrawFullScreenQuadWPOS(iWidth, iHeight);

		GetUtils().ShEndPass();

		//gcpRendD3D->FX_PopRenderTarget(0);
		//pCurrRT = pFinaltex;
		GetUtils().CopyScreenToTexture(pCurrRT);		
	}
#endif

	if( m_bInit )
	{
		m_bInit = false;
		ColorF clearColor(0, 0, 0, 0);

		pPrevRT->SetRenderTargetTile(1);
		gcpRendD3D->FX_PushRenderTarget(0, pPrevRT, NULL);		
		gcpRendD3D->EF_ClearBuffers(FRT_CLEAR_COLOR|FRT_CLEAR_IMMEDIATE, &clearColor);
		gcpRendD3D->FX_PopRenderTarget(0);		
		pPrevRT->SetRenderTargetTile(0);
	}

	gcpRendD3D->Set2DMode(false, 1, 1);           
	gcpRendD3D->RT_SetViewport(0, 0, CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());        

	if( CRenderer::CV_r_PostAAEdgeFilter < 2 && !gRenDev->m_RP.m_MSAAData.Type)
	{
		gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
		// Using offset limited re-projection + quincunx or 4x msaa

		Matrix44  pView = gcpRendD3D->m_CameraMatrix;
		pView.Transpose();

		Matrix44 pViewProj = gcpRendD3D->m_CameraProjMatrix;
		pViewProj.Transpose();

		Matrix44A mViewProjSetup = pViewProj;//gcpRendD3D->m_CameraMatrix * (GetUtils().m_pProj);      
		// mViewProjSetup.Transpose();

		const int iWidth = gcpRendD3D->GetWidth();
		const int iHeight = gcpRendD3D->GetHeight();

		Matrix44A mViewProjPrev = m_pPrevViewProj[0];                  
		mViewProjPrev.Transpose();

		Matrix44A mScaleBias = Matrix44A(	0.5f,     0,	 0,   0,
 																					0,	-0.5f,   0,   0,
																			 		0,		  0,	 1.0f,   0,						
																			0.5f ,	 0.5f,   0,   1.0f);
 		mViewProjPrev = mViewProjPrev * mScaleBias;
		mViewProjPrev.Transpose();

		GetUtils().ShBeginPass(pShader, TechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);                    

		gcpRendD3D->SetCullMode( R_CULL_NONE );
		gcpRendD3D->FX_SetState(GS_NODEPTHTEST);// | GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);   

		int nCurrID = gRenDev->GetFrameID(false)%2; // use frame id to match bilinear sample for quincux

		static CCryNameR pParam0Name("mViewProj");
		pShader->FXSetPSFloat(pParam0Name, (Vec4 *)pViewProj.GetData(), 4);     

		static CCryNameR pParam1Name("mViewProjPrev");
		pShader->FXSetPSFloat(pParam1Name, (Vec4 *)mViewProjPrev.GetData(), 4);    
			
		static CCryNameR pParam2Name("mViewPrev");
		pShader->FXSetPSFloat(pParam2Name, (Vec4 *)m_pPrevView.GetData(), 4);    
			
		if (bApplyRain)
		{
			const Vec4 vRainCol(rainInfo.m_vColor, 1.f);
			static CCryNameR pRainParam("vRainColor");
			pShader->FXSetPSFloat(pRainParam, &vRainCol, 1);
			GetUtils().SetTexture(CTexture::s_ptexRainDrops, 4, FILTER_LINEAR);
		}

		gcpRendD3D->FX_Commit();

		GetUtils().SetTexture(pPrevRT, 0, FILTER_LINEAR);
		// hack for hiding visual glitches coming from scratch texture (used for scopes)
		// in combination with amortized AA ghosting
		if (m_nScopeZoomTransition)
			GetUtils().SetTexture(pPrevRT, 1, FILTER_LINEAR);
		else
			GetUtils().SetTexture(pCurrRT, 1, FILTER_LINEAR);

		GetUtils().SetTexture(CTexture::s_ptexZTarget, 2, FILTER_POINT);      
		GetUtils().SetTexture(CTexture::s_ptexBackBuffer,3, FILTER_POINT);

		SD3DPostEffectsUtils::DrawFullScreenQuadWPOS(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

		GetUtils().ShEndPass();                    

		m_pPrevView = pView;

		if( CRenderer::CV_r_PostAAMode != 3 )
			m_pPrevViewProj[0] = mViewProjSetup;
	}
	
	gcpRendD3D->m_RP.m_PersFlags2 |= RBPF2_NOPOSTAA;

	CTexture::s_ptexBackBuffer->SetResolved(true);
	gcpRendD3D->Set2DMode(true, 1, 1);           

	gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;	
	gcpRendD3D->FX_Flush();

	PROFILE_SHADER_END
	PROFILE_LABEL_POP( "POST_AA" );
	GPU_TIMER_STOP("POST_AA");
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

bool CPostStereo::Preprocess()
{	
	return gcpRendD3D->GetS3DRend().IsPostStereoEnabled();
}

void CPostStereo::Render()
{
	CD3DStereoRenderer *const __restrict rendS3D = &gcpRendD3D->GetS3DRend();
	
	if( !rendS3D->IsPostStereoEnabled() )
		return;
	
	if( CRenderer::CV_r_PostProcessHUD3D && 
			CRenderer::CV_r_PostProcessHUD3D != 2 /* temporary code - tbr */ )
	{
		// If HUD enabled, pre-process flash updates first (for performance reasons)
		C3DHud *pPostProcessHUD3D = (C3DHud*) PostEffectMgr()->GetEffect(ePFX_3DHUD);
		pPostProcessHUD3D->FlashUpdateRT();
	}

	
	PROFILE_LABEL_PUSH( "POST_STEREO" );

	PROFILE_SHADER_START

	// Mask near geometry (weapon)
	// On D3D9 we can't officially read the device depth as on consoles, so the masking pass is required
#if !defined(XENON) && !defined(PS3)
	PROFILE_LABEL_PUSH( "NEAR_MASK" );

	CTexture *pTmpMaskTex = CTexture::s_ptexDeferredDecalTarget;
	assert(pTmpMaskTex);
	assert(pTmpMaskTex->GetWidth() == CTexture::s_ptexBackBuffer->GetWidth());
	assert(pTmpMaskTex->GetHeight() == CTexture::s_ptexBackBuffer->GetHeight());
	assert(pTmpMaskTex->GetDstFormat() == CTexture::s_ptexBackBuffer->GetDstFormat());
		
	static CCryNameTSCRC TechNameMask("StereoNearMask");

	gcpRendD3D->FX_PushRenderTarget(0, pTmpMaskTex, &gcpRendD3D->m_DepthBufferOrig);
	ColorF clearColor(1, 1, 1, 1);
	gcpRendD3D->EF_ClearBuffers(FRT_CLEAR_COLOR|FRT_CLEAR_IMMEDIATE, &clearColor);
	
	GetUtils().ShBeginPass(CShaderMan::m_shPostEffects, TechNameMask, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);
	gcpRendD3D->FX_SetState(GS_DEPTHFUNC_LEQUAL);
	SD3DPostEffectsUtils::DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight(), CRenderer::CV_r_DrawNearZRange);
	GetUtils().ShEndPass();

	gcpRendD3D->FX_PopRenderTarget(0);

	PROFILE_LABEL_POP( "NEAR_MASK" );
#endif

	const CCamera &cam = gcpRendD3D->GetCamera();
	float maxParallax = rendS3D->GetMaxSeparationScene();
	float screenDist = rendS3D->GetZeroParallaxPlaneDist() / cam.GetFarPlane();
	float nearGeoShift = rendS3D->GetNearGeoShift() / cam.GetFarPlane();
	float nearGeoScale = rendS3D->GetNearGeoScale();

	static CCryNameTSCRC TechName("PostStereo");

	rendS3D->BeginRenderingMRT(true);

	GetUtils().ShBeginPass(CShaderMan::m_shPostEffects, TechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);

	gcpRendD3D->FX_SetState(GS_NODEPTHTEST);

	static CCryNameR pParamName0("StereoParams");
	Vec4 stereoParams(maxParallax, screenDist, nearGeoShift, nearGeoScale);
	CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName0, &stereoParams, 1);

	static CCryNameR pParamName1("NearZRange");
	Vec4 nearZRange(CRenderer::CV_r_DrawNearZRange, CRenderer::CV_r_DrawNearZRange, CRenderer::CV_r_DrawNearZRange, CRenderer::CV_r_DrawNearZRange);
	CShaderMan::m_shPostEffects->FXSetPSFloat(pParamName1, &nearZRange, 1);

	GetUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_LINEAR, TADDR_MIRROR);
	GetUtils().SetTexture(CTexture::s_ptexZTarget, 1, FILTER_POINT);
#if !defined(XENON) && !defined(PS3)
	GetUtils().SetTexture(pTmpMaskTex, 2, FILTER_POINT);
#endif
	
	SD3DPostEffectsUtils::DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

	GetUtils().ShEndPass();
	rendS3D->EndRenderingMRT(false);

	gcpRendD3D->FX_Flush();
	PROFILE_SHADER_END

	PROFILE_LABEL_POP( "POST_STEREO" );
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CImageGhosting::Render()
{
	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);
	
	CTexture *pPrevFrame = CTexture::s_ptexPrevFrameScaled;
	CTexture *pPrevFrameRead = CTexture::s_ptexPrevFrameScaled;

	if( m_bInit )
	{
		m_bInit = false;
		ColorF clearColor(0, 0, 0, 0);
		
		pPrevFrame->SetRenderTargetTile(1);
		gcpRendD3D->FX_PushRenderTarget(0, pPrevFrame, NULL);		
		gcpRendD3D->EF_ClearBuffers(FRT_CLEAR_COLOR|FRT_CLEAR_IMMEDIATE, &clearColor);
		gcpRendD3D->FX_PopRenderTarget(0);		
		pPrevFrame->SetRenderTargetTile(0);
	}

	PROFILE_LABEL_PUSH( "IMAGE_GHOSTING" );

	// 0.25ms / 0.4ms
	static CCryNameTSCRC TechName("ImageGhosting");
	GetUtils().ShBeginPass(CShaderMan::m_shPostEffects, TechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);                    

	// Update ghosting     
	gcpRendD3D->FX_SetState(GS_NODEPTHTEST|GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA);   

	static CCryNameR pParamNamePS("ImageGhostingParamsPS");
	Vec4 vParamsPS = Vec4(1, 1, max(0.0f, 1-m_pAmount->GetParam()), gEnv->pTimer->GetFrameTime());                 
	CShaderMan::m_shPostEffects->FXSetPSFloat(pParamNamePS, &vParamsPS, 1);

	GetUtils().SetTexture(pPrevFrameRead, 0, FILTER_LINEAR);        

	GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

	GetUtils().ShEndPass();   

	// todo: on x360 use msaa (0.1ms overall)
	pPrevFrame->SetRenderTargetTile(1); 
	GetUtils().CopyScreenToTexture(CTexture::s_ptexBackBuffer);			// 0.25ms / 0.4 ms
	GetUtils().StretchRect(CTexture::s_ptexBackBuffer, pPrevFrame);	// 0.25ms
	pPrevFrame->SetRenderTargetTile(0); 

	PROFILE_LABEL_POP( "IMAGE_GHOSTING" );
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CUberGamePostProcess::Render()
{
	PROFILE_LABEL_PUSH( "UBER_GAME_POSTPROCESS" );

	uint64 nSaveFlagsShader_RT = gRenDev->m_RP.m_FlagsShader_RT;
	gRenDev->m_RP.m_FlagsShader_RT &= ~(g_HWSR_MaskBit[HWSR_SAMPLE0]|g_HWSR_MaskBit[HWSR_SAMPLE1]|g_HWSR_MaskBit[HWSR_SAMPLE2]);

	gRenDev->m_cEF.mfRefreshSystemShader("PostEffectsGame", CShaderMan::m_shPostEffectsGame);
	
	if( m_nCurrPostEffectsMask & ePE_ChromaShift )
		gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE0];
	//if( m_nCurrPostEffectsMask & ePE_RadialBlur )
	//	gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE1];
	if( m_nCurrPostEffectsMask & ePE_SyncArtifacts )
		gRenDev->m_RP.m_FlagsShader_RT |= g_HWSR_MaskBit[HWSR_SAMPLE2];

	static CCryNameTSCRC TechName("UberGamePostProcess");
	GetUtils().ShBeginPass(CShaderMan::m_shPostEffectsGame, TechName, FEF_DONTSETTEXTURES | FEF_DONTSETSTATES);                    

	CTexture *pMaskTex = const_cast<CTexture *> (static_cast<CParamTexture*>(m_pMask)->GetParamTexture());
	
	int32 nRenderState = GS_NODEPTHTEST;

	// Blend with backbuffer when user sets a mask
	if( pMaskTex)
		nRenderState |= GS_BLSRC_SRCALPHA | GS_BLDST_ONEMINUSSRCALPHA;

	gcpRendD3D->FX_SetState(nRenderState);   

	Vec4 cColor = m_pColorTint->GetParamVec4();
	static CCryNameR pParamNamePS0("UberPostParams0");
  static CCryNameR pParamNamePS1("UberPostParams1");
  static CCryNameR pParamNamePS2("UberPostParams2");
  static CCryNameR pParamNamePS3("UberPostParams3");
  static CCryNameR pParamNamePS4("UberPostParams4");
  static CCryNameR pParamNamePS5("UberPostParams5");

	Vec4 vParamsPS[6] =  
	{
		Vec4(m_pVSyncAmount->GetParam(), m_pInterlationAmount->GetParam(), m_pInterlationTilling->GetParam(), m_pInterlationRotation->GetParam() ),
		//Vec4(m_pVSyncFreq->GetParam(), 1.0f + max(0.0f, m_pPixelationScale->GetParam()*0.25f), m_pNoise->GetParam()*0.25f, m_pChromaShiftAmount->GetParam() + m_pFilterChromaShiftAmount->GetParam()),
		Vec4(m_pVSyncFreq->GetParam(), 1.0f, m_pNoise->GetParam()*0.25f, m_pChromaShiftAmount->GetParam() + m_pFilterChromaShiftAmount->GetParam()),
		Vec4(min(1.0f, m_pGrainAmount->GetParam() * 0.1f*0.25f), m_pGrainTile->GetParam(), m_pSyncWavePhase->GetParam(), m_pSyncWaveFreq->GetParam()),		
		Vec4(cColor.x, cColor.y, cColor.z, min(1.0f, m_pSyncWaveAmplitude->GetParam() * 0.01f )),
		Vec4(cry_frand(), cry_frand(), cry_frand(),  cry_frand()),
		Vec4(0, 0, 0, 0)
	}; 

  // temp workaround for shader constants messup with arrays on ps3
  //CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS, vParamsPS, 6);

	CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS0, &vParamsPS[0], 1);
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS1, &vParamsPS[1], 1);
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS2, &vParamsPS[2], 1);
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS3, &vParamsPS[3], 1);
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS4, &vParamsPS[4], 1);
  CShaderMan::m_shPostEffectsGame->FXSetPSFloat(pParamNamePS5, &vParamsPS[5], 1);


	GetUtils().SetTexture(CTexture::s_ptexBackBuffer, 0, FILTER_LINEAR);
	GetUtils().SetTexture(CTexture::s_ptexScreenNoiseMap, 1, FILTER_LINEAR, 0);

	if( pMaskTex )
		GetUtils().SetTexture(pMaskTex, 2, FILTER_LINEAR);
	else
		GetUtils().SetTexture(CTexture::s_ptexWhite, 2, FILTER_LINEAR);

	GetUtils().DrawFullScreenQuad(CTexture::s_ptexBackBuffer->GetWidth(), CTexture::s_ptexBackBuffer->GetHeight());

	GetUtils().ShEndPass();   

	m_nCurrPostEffectsMask = 0;
	gRenDev->m_RP.m_FlagsShader_RT = nSaveFlagsShader_RT;

	PROFILE_LABEL_POP( "UBER_GAME_POSTPROCESS" );
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////

void CSoftAlphaTest::Render()
{
	PROFILE_LABEL_PUSH( "SOFT ALPHA TEST" );

	CRendElementBase *pPrevRE = gRenDev->m_RP.m_pRE;			
	gRenDev->m_RP.m_pRE = NULL;





	gcpRendD3D->Set2DMode(false, 1, 1);     

	gcpRendD3D->FX_ProcessSoftAlphaTestRenderLists();
	
	gcpRendD3D->Set2DMode(true, 1, 1);     





	gRenDev->m_RP.m_pRE = pPrevRE;

	PROFILE_LABEL_POP( "SOFT ALPHA TEST" );
}
